package com.example.demo.account.service.impl;

import com.example.demo.account.entity.SecurityUser;
import com.example.demo.account.entity.SysUser;
import com.example.demo.account.entity.SysUserRole;
import com.example.demo.account.repository.RoleRepository;
import com.example.demo.account.repository.UserRepository;
import com.example.demo.account.service.UserRoleService;
import com.example.demo.account.repository.UserRoleRepository;
import com.example.demo.account.service.UserService;
import com.example.demo.common.service.CustomerDetailService;
import com.example.demo.common.utils.BCryptUtil;
import com.example.demo.common.utils.Constant;
import com.example.demo.information.entity.Student;
import org.hibernate.service.spi.ServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * 描述：
 *
 * @author littlecar
 * @date 2019/9/5 10:32
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class UserServiceImpl implements UserService {
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private RoleRepository roleRepository;
    @Autowired
    private CustomerDetailService customerDetailService;
    @Autowired
    private BCryptPasswordEncoder passwordEncoder;
    @Autowired
    private UserRoleService userRoleService;
    @Autowired
    private UserRoleRepository userRoleRepository;

    @Override
    public SysUser findByUsername(String username) {
        return  userRepository.findByUsername(username);
    }

    @Override
    public List<SysUser> findAll() {
        return userRepository.findAll();
    }
    @Override
    public List<SysUser> findPageAll(Integer pages,Integer limit) {
        return userRepository.findPageAll(pages,limit);
    }

    @Override
    public void save(SysUser user) {
        userRepository.save(user);
    }

    @Override
    public void delete(SysUser user) {
        userRepository.delete(user);
    }

    @Override
    public List<SysUser> findByUsernameLike(String username) {
        return userRepository.findByUsernameLike(username);
    }

    @Override
    public Optional<SysUser> findById(Long id) {
        return userRepository.findById(id);
    }

    /**
     * 确认用户角色选择后进行登录
     * @param userRoleId
     * @param request
     * @param currentUserDetails
     * @return
     */
    @Override
    public HttpServletRequest doRoleChoose(Long userRoleId, HttpServletRequest request, SecurityUser currentUserDetails) {
        SysUserRole userRole = userRoleService.findById(userRoleId);
        String roleName = Constant.roleIdMap.get(userRole.getRole_id());
        Collection<GrantedAuthority> authorities = new LinkedHashSet<>();
        SimpleGrantedAuthority authority = new SimpleGrantedAuthority(Constant.Role_prefix + roleName);
        authorities.add(authority);
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(currentUserDetails.getUsername()+"@@@"+userRoleId.toString(), currentUserDetails.getUserPwd(), authorities);
        try{
            token.setDetails(new WebAuthenticationDetails(request));
            DaoAuthenticationProvider authenticator = new DaoAuthenticationProvider();
            authenticator.setUserDetailsService(customerDetailService);
            authenticator.setPasswordEncoder(passwordEncoder);
            Authentication authentication = authenticator.authenticate(token);
            SecurityContextHolder.getContext().setAuthentication(authentication);

            request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY,SecurityContextHolder.getContext());
            return request;
        }catch (AuthenticationException e){
            e.printStackTrace();
            throw new ServiceException(e.getMessage());
        }
    }

    @Override
    public List<SysUser> findByNameLike(String name) {
        return userRepository.findByNameLike(name);
    }
    @Override
    public List<SysUser> findPageByNameLike(String name,Integer page,Integer limit) {
        return userRepository.findPageByNameLike(name,page,limit);
    }

    @Override
    public SysUser findByName(String name) {
        return userRepository.findByName(name);
    }

    @Override
    public List<SysUser> findBySfz(String sfz) {
        return userRepository.findBySfz(sfz);
    }

    @Override
    public String createUserForStu(Student student) {
        SysUser user = new SysUser(student);
        user.setUsername(user.getSfz());
        user.setPassword(BCryptUtil.encode(user.getSfz().substring(user.getSfz().length() - 8, user.getSfz().length())));
        SysUser oldUser = userRepository.findByUsername(user.getUsername());
        Set<SysUserRole> sysUserRoles = new HashSet<SysUserRole>();
        boolean flag = true;
        if(oldUser!=null){
            user = oldUser;
            sysUserRoles = user.getSysUserRoles();
            for(SysUserRole role :sysUserRoles){
                if(role.getRole_id()==Constant.STUDENT_ID&&role.getSchool_id().equals(student.getSchool().getId())){
                    flag = false;
                }
            }
        }
        if(flag){
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setRole_id(Constant.STUDENT_ID);
            sysUserRole.setSchool_id(student.getSchool().getId());
            userRoleRepository.save(sysUserRole);
            sysUserRoles.add(sysUserRole);
            user.setSysUserRoles(sysUserRoles);
        }
        try{
            userRepository.save(user);
            return "success";
        } catch (Exception e) {
            e.printStackTrace();
            return "error";
        }
    }

    @Override
    public void deleteXsAuth(Student student) {
        SysUser sysUser = userRepository.findByUsername(student.getSfz());
        if(sysUser==null){
            return;
        }
        Set<SysUserRole> roleSet = sysUser.getSysUserRoles();
        if(roleSet.size()==1){
            userRepository.delete(sysUser);
            return;
        }
        SysUserRole temp = null;
        for(SysUserRole role : roleSet){
            if(student.getSchool().getId().equals(role.getSchool_id())
                &&role.getRole_id()==Constant.STUDENT_ID){
                temp = role;break;
            }
        }
        roleSet.remove(temp);
        sysUser.setSysUserRoles(roleSet);
        userRepository.save(sysUser);
    }

    @Override
    public List<SysUser> findAllSchoolAdmin() {
        return userRepository.findAllSchoolAdmin();
    }

    @Override
    public List<SysUser> findPageSchoolAdminByNameLike(String admin_name, int pages, int limit) {
        return userRepository.findPageSchoolAdminByNameLike(admin_name,pages,limit);
    }

    @Override
    public List<SysUser> findSchoolAdminByNameLike(String admin_name) {
        return userRepository.findSchoolAdminByNameLike(admin_name);
    }

    @Override
    public List<SysUser> findPageAllSchoolAdmin(int pages, int limit) {
        return userRepository.findPageAllSchoolAdmin(pages,limit);
    }

    @Override
    public List<SysUser> findUserBySchoolIdAndRoleId(Long school_id, Long role_id) {
        return userRepository.findUserBySchoolIdAndRoleId(school_id,role_id);
    }

    @Override
    public List<SysUser> findPageBzrByNameLike(String bzr_name, Long xxxx_id, int pages, int limit) {
        return userRepository.findPageBzrByNameLike(bzr_name, xxxx_id, pages, limit);
    }

    @Override
    public List<SysUser> findBzrByNameLike(String bzr_name, Long xxxx_id) {
        return userRepository.findBzrByNameLike(bzr_name, xxxx_id);
    }

    @Override
    public List<SysUser> findPageAllBzr(Long xxxx_id, int pages, int limit) {
        return userRepository.findPageAllBzr(xxxx_id, pages, limit);
    }

    @Override
    public List<SysUser> findAllBzr(Long xxxx_id) {
        return userRepository.findAllBzr(xxxx_id);
    }

}
